#! /bin/bash
# Custom Bru LTO write script

PATH=$PATH:/bru
export PATH

. brufunclib

LTO_BASE_DIR="/Volumes/Stage"
BLOCKSIZE_K=1024
BRU_HOME=/Users/backupuser/bru
BRUTAB=${BRU_HOME}/etc/brutab
BRUXPAT=${BRU_HOME}/etc/bruxpat
BACKUP_USER=backupuser
BACKUP_GROUP=staff
BACKUP_PERM=755

export BRUTAB
export BRUXPAT

echo ""
echo "****************** BRU LTO Backup Script ******************"
echo ""

fnPerformChecks()
{
	# Check that bru_home dir exists
	if [ ! -d "$BRU_HOME" ]; then
		echo "Bru working directory $BRU_HOME could not be found."
		echo "Script terminated."
		echo ""	
		exit
	fi

	IS_BASEDIR="n"
	while [ $IS_BASEDIR == "n" ]
	do
		echo -n "Enter Staging Disk number (1/2):"
		read LTO_STAGE
		echo $LTO_STAGE | grep "^[12]$" > /dev/null
		if [ $? -eq 0 ]; then
			IS_BASEDIR="y"
		fi
	done

	LTO_BASE_DIR=${LTO_BASE_DIR}$LTO_STAGE

	# cd to LTO_BASE_DIR so we can backup files using relative pathnames
	if [ -d "$LTO_BASE_DIR" ]; then
		cd "$LTO_BASE_DIR"
	else
		echo "$LTO_BASE_DIR could not be found."
		echo "Script terminated."
		echo ""
		exit
	fi

	IS_GEN="n"
	while [ $IS_GEN == "n" ]
	do
		echo -n "Enter LTO tape generation (3/4):"
		read LTO_GEN
		echo $LTO_GEN | grep "^[34]$" > /dev/null
		if [ $? -eq 0 ]; then
			IS_GEN="y"
		fi
	done

	# cd to LTO_GEN subdir
	if [ -d "$LTO_BASE_DIR/LTO-$LTO_GEN" ]; then
		cd "LTO-$LTO_GEN"
	else
		echo "$LTO_BASE_DIR/LTO-$LTO_GEN could not be found."
		echo "Script terminated."
		echo ""
		exit
	fi

	if [ $LTO_GEN == "4" ]; then
		LTO_SIZE=765
	elif [ $LTO_GEN == "3" ]; then
		LTO_SIZE=373
	fi

	echo "LTO-$LTO_GEN Tape capacity is $LTO_SIZE Gb"
	echo ""

	IS_NUM="n"
	while [ $IS_NUM == "n" ]
	do
		echo -n "Enter LTO-$LTO_GEN index number:"
		read LTO_INDEX
		echo $LTO_INDEX | grep "^[0-9][0-9]*$" > /dev/null
		if [ $? -eq 0 ]; then
			IS_NUM="y"
		fi
	done

	# cd to LTO_INDEX subdir
	if [ -d "$LTO_BASE_DIR/LTO-$LTO_GEN/$LTO_INDEX" ]; then
		cd "$LTO_INDEX"
	else
		echo "$LTO_BASE_DIR/LTO-$LTO_GEN/$LTO_INDEX could not be found."
		echo "Script terminated."
		echo ""
		exit
	fi

	if [ "$(ls | wc -l)" -eq 0 ]; then
		echo "$(pwd) is EMPTY."
		echo "Script terminated."
		echo ""
		exit
	else
		echo "$(pwd) contains:"
		echo ""
		echo "$(ls -lp)"
		echo ""
	fi

	# Check for non-standard chars and spaces in folder names
	# Maybe good to make this recursive later 

	for f in *
	do
		if [ -d "$f" ]; then
			echo "$f" | grep "^[a-zA-Z0-9_-][a-zA-Z0-9_-]*$" > /dev/null
			if [ $? -ne 0 ]; then
				echo "The following directory name contains invalid characters."
				echo "$f"
				echo "Script terminated."
				echo ""
				exit
			fi
		else
			echo "$f" | grep "^[a-zA-Z0-9_-][a-zA-Z0-9_-]*\.[a-zA-Z0-9_-]\{3\}$" > /dev/null
			if [ $? -ne 0 ]; then
				echo "The following file name contains invalid characters or is not in the correct format."
				echo "$f"
				echo "Script terminated."
				echo ""
				exit
			fi
		fi
	done


	# Warn user if any folder is less than 100MB
	
	LOW_DIR_SIZE_WARN_LIMIT=100
	for f in *
	do
		if [ -d "$f" ]; then
			mb=$(du -d0 -m "$f" | cut -f 1)
			if [ $(echo "scale=2; $mb < $LOW_DIR_SIZE_WARN_LIMIT" | bc) -eq 1 ]; then
				echo "WARNING: The size of directory $f is $mb MB!"
				echo ""
				dirs_ok="n"
				while [ $dirs_ok == "n" ]
				do
					echo -n "Proceed (y/n)?"
					read ok
					ok=$(echo $ok | tr '[:upper:]' '[:lower:]')
					echo $ok | grep "^[yn]$" > /dev/null
					if [ $? -eq 0 ]; then
						if [ $ok == "n" ]; then
							echo "Script terminated by user."
							echo ""
							exit
						elif [ $ok == "y" ]; then
							dirs_ok="y"
						fi
					fi
				done	
			fi
		fi
	done
	echo ""


	# Check that file owner and group is set correctly

	STDIZE_SET="n"
	while [ $STDIZE_SET == "n" ]
	do
		echo -n "Standardize the owner, group and permissions for all files/directories [Recommended] (y/n)?"
		read DO_STDIZE
		echo $DO_STDIZE | grep "^[yn]$" > /dev/null
		if [ $? -eq 0 ]; then
			STDIZE_SET="y"

			if [ $DO_STDIZE == "y" ]; then
	
				$(chown -R $BACKUP_USER .)
				if [ $? -ne 0 ]; then
					echo "Unable to change owner on all files."
				fi

				$(chgrp -R $BACKUP_GROUP .)
				if [ $? -ne 0 ]; then
					echo "Unable to change group on all files."
				fi
	
				# Check that file permissions are set correctly
				$(chmod -R $BACKUP_PERM .)
				if [ $? -ne 0 ]; then
					echo "Unable to change group on all files."
				fi

				# Remove the ACL attributes from all files
				$(chmod -R -N .)
				if [ $? -ne 0 ]; then
					echo "Unable to remove ACLs on all files and directories."
				fi

				echo "Done"

			elif [ $DO_STDIZE == "n" ]; then
				echo "Owner, group and permissions NOT standardized"
			fi
		fi
	done

	echo ""
	echo "$(ls -lp)"
	echo ""

}


fnOperationProgress()
{
	if [ $1 == "c" ]; then
		msg_str="Archived"
	elif [ $1 == "i" ]; then
		msg_str="Verified"
	fi
	replace="n"
	while read line
	do
		echo "$line" | grep "^VL:$1" > /dev/null
		if [ $? -eq 0 ]; then
			secs=$(echo -n "$(date +%s)")
			elapsed_secs=$(echo -n "$[$secs - $start_secs]")	
			size_k=$(echo $line | cut -f 2 -d "|")
			size_m=$(echo "scale=2; $size_k / 1024" | bc)		
			size_g=$(echo "scale=2; $size_m / 1024" | bc)
			pcent=$(echo "scale=1; $size_k * 100 / $backup_size_k" | bc)
			elapsed_time=$(date -ur $elapsed_secs +%H:%M:%S)
			mbps=$(echo "scale=1; $size_m / $[$elapsed_secs + 1]" | bc)
			if [ $replace == "n" ]; then
				echo ""
			fi
			if [ $replace == "y" ]; then
				
				tput dl	
				tput cuu1
			fi
			echo "$msg_str $size_g Gb (${pcent}%) in $elapsed_time at $mbps Mbps"
			replace="y"
		else
			echo "$line" | grep "^P:" > /dev/null
			if [ $? -ne 0 ]; then
				if [ $replace == "y" ]; then
					tput dl

					tput cuu1
				fi
				echo "$line"
				replace="n"
			fi
		fi
	done
}

fnEstimateSize()
{
	while read line
	do
		k=$(echo $line | cut -f 4 -d "," | cut -f 2 -d " ")
		echo $k
	done
}

fnRecordTape()
{
	# Run BRU Estimate backup size script
	echo ""
	echo "Estimating backup size"

	# Need to assign variable to output of command due to variable scope problem when using pipe to while-read-line 
	backup_size_k=$(ls | bru -elvvvvvvvvv -m -QX -f ntape$1 - | tail -n17 | head -n1 | fnEstimateSize)
	backup_size_g=$(echo "scale=2; $backup_size_k / 1048576" | bc)
	echo $backup_size_g Gb
	echo ""

	# Exit if estimated backup size exceeds tape capacity
	if [ $(echo "scale=2; $backup_size_g > $LTO_SIZE" | bc) -eq 1 ]; then
		echo "Estimated backup size exceeds the capacity of the LTO tape."
		echo "Script terminated".
		echo ""
		exit
	fi

	drive_ready="n"
	while [ $drive_ready == "n" ]
	do
		echo -n "Proceed with backup (y/n)? [THIS WILL OVERWRITE ALL DATA STORED ON THE TAPE]:"
		read proceed
		proceed=$(echo $proceed | tr '[:upper:]' '[:lower:]')
		echo $proceed | grep "^[yn]$" > /dev/null
		if [ $? -eq 0 ]; then
			if [ $proceed == "n" ]; then
				echo "Script terminated by user."
				echo ""
				exit
			elif [ $proceed == "y" ]; then
				drive_ready="y"
			fi
		fi
	done

	echo ""
	echo "Rewinding tape ..."
	fnRewindTape $1

	# Run BRU write data script

	echo ""
	echo "Writing tape"
	echo ""

	LTO_LABEL=$LTO_GEN$(printf %03d $LTO_INDEX)

	pid_hex=$(echo "obase=16; $$"| bc)
	start_secs="$(date +%s)"

	ls | bru -clvvvvvvvvv -O -m -R -j -L $LTO_LABEL -QX -A -b ${BLOCKSIZE_K}K -f ntape$1 - | tee ${BRU_HOME}/tmp/$pid_hex | fnOperationProgress "c"

	stop_secs="$(date +%s)"
	elapsed_secs=$(echo -n "$(expr $stop_secs - $start_secs)")	
	backup_time=$(date -ur $elapsed_secs +%H:%M:%S)

	echo ""
	echo "Backup took $backup_time"
	echo ""

	archive_id=$(sed -n '1p' ${BRU_HOME}/tmp/$pid_hex | cut -f 4 -d " ")

	# Remove all lines starting with "P:" - bug in bru software
	cd $BRU_HOME
	sed '/^P:/d' < tmp/$pid_hex > tmp/BRU-$archive_id
	rm tmp/$pid_hex
	gzip -c tmp/BRU-$archive_id > catalog/BRU-${archive_id}.gz
	rm tmp/BRU-$archive_id

	# Append catalog to end of tape
	echo "Appending copy of catalog BRU-${archive_id}.gz to tape"
	echo ""
	cd catalog
	bru -cf ntape$1 -L "#CATALOG - $archive_id" -b ${BLOCKSIZE_K}K -QB BRU-${archive_id}.gz

	# Rewind tape
	echo "Rewinding tape ..."
	fnRewindTape $1

	# Verify tape
	echo "Verifying tape"
	echo ""

	start_secs="$(date +%s)"

	bru -ivvvvvvvvv -j -b ${BLOCKSIZE_K}K -f ntape$1 | fnOperationProgress "i"

	stop_secs="$(date +%s)"
	elapsed_secs=$(echo -n "$[$stop_secs - $start_secs]")	
	verify_time=$(date -ur $elapsed_secs +%H:%M:%S)
	echo ""
	echo "Verification took $verify_time"
	echo ""

	echo "Rewinding tape ..."
	fnRewindTape $1
	echo ""
	echo "Ejecting tape ..."
	fnEjectTape $1

	echo ""
	echo "DONE!"
	echo ""
	echo "[Please label tape]"
	echo ""
	exit
}


fnMain()
{
	echo ""
	echo -n "Please insert a blank tape into an available drive and press Enter, (or \"q\" to quit)"
	read INPUT
	echo $INPUT | grep "^q$" > /dev/null
	if [ $? -eq 0 ]; then
		echo ""
		exit
	else
		fnLoadTape 0 "TRUE" "OFF"
	fi

	if [ $LOAD_STATUS == "DRIVE_EMPTY" ]; then
		fnMain
		return 0
	fi

	if [ $LOAD_STATUS == "TAPE_PROTECTED" ]; then
		echo "Please remove write-protection before proceeding"
		echo ""
		echo "Ejecting tape in drive $CURRENT_DRIVE..."
		fnEjectTape $CURRENT_DRIVE
		fnMain 
		return 0
	fi	

	fnCheckTapeLabel $CURRENT_DRIVE

	if [ $LABEL != "UNDEFINED" ]; then
		VALID_INPUT="n"
		while [ $VALID_INPUT == "n" ]
		do
			echo ""
			echo -n "Do you want to overwrite the tape (y/n)?"
			read PROCEED
			proceed=$(echo $proceed | tr '[:upper:]' '[:lower:]')
			echo $PROCEED | grep "^[yn]$" > /dev/null
			if [ $? -eq 0 ]; then
				VALID_INPUT="y"
				if [ $PROCEED != "y" ]; then
					echo ""
					echo "Ejecting tape ..."
					fnEjectTape $CURRENT_DRIVE 
					fnMain
					return 0			
				else
					fnRecordTape $CURRENT_DRIVE
					return 0
				fi
			fi	
		done
	else
		fnRecordTape $CURRENT_DRIVE
	fi
}

fnPerformChecks
fnMain

